package protocol.control;

import protocol.Frame;

public class Packet implements Frame {
	
	/**
	 * The packet type
	 */
	private byte type;
	/**
	 * Flags, used in connection initialization
	 */
	private byte flags;
	/**
	 * This is either 
	 *  - a send request packet,
	 *  - a send info packet,
	 *  - a receive request packet or 
	 *  - a receive info packet
	 */
	private Frame data;
	
	public byte getType() {
		return this.type;
	}

	public void setType(byte type) {
		this.type = type;
	}

	public byte getFlags() {
		return this.flags;
	}

	public void setFlags(byte flags) {
		this.flags = flags;
	}

	public Frame getData() {
		return this.data;
	}

	public void setData(Frame data) {
		this.data = data;
	}
	
	/**
	 * Constructor
	 */
	public Packet() {
	}
	
	/**
	 * Constructor
	 * @param bytes Supplied for method parse()
	 */
	public Packet(byte[] bytes) {
		this.parse(bytes);
	}

	public byte[] build() {
		/**
		 * Get the data length,
		 * which varies between different packet types
		 */
		int datalength = 0;
		if (this.getType() == 1) datalength = 257; // send request packet
		if (this.getType() == 2) datalength = 320; // send info packet
		if (this.getType() == 3) datalength = 319; // receive request packet
		if (this.getType() == 4) datalength = 258; // receive info packet
		/**
		 * Set the header fields and initialize the byte array
		 */
		byte[] data = new byte[datalength + 2];
		data[0] = (byte)this.getType();
		data[1] = (byte)this.getFlags();
		/**
		 * Set the data
		 */
		if (this.getData() == null) {
			// there's no data when doing 
			// connection initialization / shutdown
		} else {
			System.arraycopy(
				this.getData().build(), 0, // source
				data, 2, // destination
				datalength); // copy length
		}
		return data;
	}

	public void parse(byte[] bytes) {
		/**
		 * Save the packet type
		 */
		this.setType(bytes[0]);
		/**
		 * Save the flags
		 */
		this.setFlags(bytes[1]);
		/**
		 * Parse the inner packest
		 * Packet type 1 -> SendRequestPacket
		 */
		if (this.getType() == 0) {
			this.setData(null);
		} else if (this.getType() == 1) {
			byte[] data = new byte[257];
			System.arraycopy(
				bytes, 2, // source
				data, 0, // destination
				257); // copy length
			this.setData(new SendRequestPacket(data));
		} else if (this.getType() == 2) {
			/**
			 * Packet type 2 -> SendInfoPacket
			 */
			byte[] data = new byte[320];
			System.arraycopy(
				bytes, 2, // source
				data, 0, // destination
				320); // copy length
			this.setData(new SendInfoPacket(data));
		} else if (this.getType() == 3) {
			/**
			 * Packet type 3 -> ReceiveRequestPacket
			 */
			byte[] data = new byte[319];
			System.arraycopy(
				bytes, 2, // source
				data, 0, // destination
				319); // copy length
			this.setData(new ReceiveRequestPacket(data));
		} else if (this.getType() == 4) {
			/**
			 * Packet type 4 -> ReceiveInfoPacket
			 */
			byte[] data = new byte[258];
			System.arraycopy(
				bytes, 2, // source
				data, 0,  // destination
				258); // copy length
			this.setData(new ReceiveInfoPacket(data));
		}
	}

}